package com.huimei.hmc.upms.sys.web.controller;

import com.huimei.hmc.common.base.BaseResult;
import com.huimei.hmc.common.util.RedisUtil;
import com.huimei.hmc.upms.client.common.base.BaseUpmsController;
import com.huimei.hmc.upms.client.shiro.session.UpmsSession;
import com.huimei.hmc.upms.client.shiro.session.UpmsSessionDao;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.UUID;

/**
 * Created by Huangyuheng on 2017/7/6.
 */
@Controller
@RequestMapping("/sso")
public class SSOController extends BaseUpmsController {

    /**
     * 全局会话key
     */
    private final static String HMC_UPMS_SERVER_SESSION_ID = "hmc-upms-server-session-id";

    /**
     * 全局会话key列表
     */
    private final static String HMC_UPMS_SERVER_SESSION_IDS = "hmc-upms-server-session-ids";

    /**
     * code key
     */
    private final static String HMC_UPMS_SERVER_CODE = "hmc-upms-server-code";

    @Autowired
    private UpmsSessionDao upmsSessionDao;

    @RequestMapping(value = "/index")
    public String index(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
        logger.info("index");

        String appId = request.getParameter("appId");
        String backurl = request.getParameter("backurl");

        if (StringUtils.isBlank(appId)) {
            throw new RuntimeException("无效访问！");
        }

        return "redirect:/sso/login?backurl=" + URLEncoder.encode(backurl, "utf-8");
    }

    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String login(HttpServletRequest request, HttpServletResponse response){

        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        String serverSessionId = session.getId().toString();

        // 判断是否已登录，如果已登录，则回跳
        String code = RedisUtil.get(HMC_UPMS_SERVER_SESSION_ID + "_" + serverSessionId);

        String backurl = request.getParameter("backurl");

        // code校验值
        if (StringUtils.isNotBlank(code)) {

            String username = (String) subject.getPrincipal();

            if (StringUtils.isBlank(backurl)) {
                backurl = "/";
            } else {
                if (backurl.contains("?")) {
                    backurl += "&upmsCode=" + code + "&upmsUsername=" + username;
                } else {
                    backurl += "?upmsCode=" + code + "&upmsUsername=" + username;
                }
            }
            logger.debug("认证中心帐号通过，带code回跳：{}", backurl);
            return "redirect:" + backurl;
        }

        request.setAttribute("backurl", backurl);

        return "sso/login";
    }

    @RequestMapping(value = "/login", method = RequestMethod.POST)
    @ResponseBody
    public BaseResult login(HttpServletRequest request){

        String username = request.getParameter("username");
        String password = request.getParameter("password");

        if (StringUtils.isBlank(username)) {
            return BaseResult.fail("用户不能为空");
        }
        if (StringUtils.isBlank(password)) {
            return BaseResult.fail("密码不能为空！");
        }

        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        String serverSessionId = session.getId().toString();

        // 判断是否已登录，如果已登录，则回跳，防止重复登录
        String hasCode = RedisUtil.get(HMC_UPMS_SERVER_SESSION_ID + "_" + serverSessionId);

        if (StringUtils.isBlank(hasCode)) {
            // 使用shiro认证
            UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password);

            try {
                subject.login(usernamePasswordToken);
            }  catch (UnknownAccountException e) {
                return BaseResult.fail("帐号或密码错误不存在！");
            } catch (IncorrectCredentialsException e) {
                return BaseResult.fail("帐号或密码错误不存在");
            } catch (LockedAccountException e) {
                return BaseResult.fail("帐号已锁定！");
            }

            // 更新session状态
            upmsSessionDao.updateStatus(serverSessionId, UpmsSession.OnlineStatus.ONLINE);
            //默认验证帐号密码正确，创建code
            String code = UUID.randomUUID().toString();


            // 全局会话的code
            RedisUtil.set(HMC_UPMS_SERVER_SESSION_ID + "_" + serverSessionId, code, (int) subject.getSession().getTimeout() / 1000);
            // code校验值
            RedisUtil.set(HMC_UPMS_SERVER_CODE + "_" + code, code, (int) subject.getSession().getTimeout() / 1000);
        }

        // 回跳登录前地址
        String backurl = request.getParameter("backurl");
        if (StringUtils.isBlank(backurl)) {
            return BaseResult.success(1, "/", "success");
        } else {
            return BaseResult.success(1, backurl, "success");
        }
    }

    @RequestMapping(value = "/code", method = RequestMethod.POST)
    @ResponseBody
    public Object code(HttpServletRequest request) {
        String codeParam = request.getParameter("code");
        String code = RedisUtil.get(HMC_UPMS_SERVER_CODE + "_" + codeParam);
        if (StringUtils.isBlank(codeParam) || !codeParam.equals(code)) {
            return BaseResult.fail("无效code");
        }

        return BaseResult.success(1, code, "success");
    }

    @RequestMapping(value = "/logout", method = RequestMethod.GET)
    @ResponseBody
    public BaseResult logout(HttpServletRequest request, HttpServletResponse response){
        logger.info("logout");

        // shiro退出登录
        SecurityUtils.getSubject().logout();

        // 跳回原地址
        String redirectUrl = request.getHeader("Referer");
        if (null == redirectUrl) {
            redirectUrl = "/";
        }

        return BaseResult.success(1, redirectUrl, "success");
    }

}
